package com.supercell.misc.concurrent;

import com.supercell.misc.data.TCPConnectionStatus;
import com.supercell.service.DataManipulationService;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;

/**
 * Created by WUJO2 on 7/15/2016.
 */
public class TCPServer extends Thread {
    private static TCPServer tcpServer;
    private ServerSocket serverSocket;
    private List<Socket> clientSockets;
    private List<TCPConnectionStatus> tcpConnectionStatusList;
    private List<Thread> connectionThreadList;
    private DataManipulationService dataManipulationService;

    private TCPServer(
            int tcpPortNumber,
            DataManipulationService dataManipulationService,
            List<TCPConnectionStatus> tcpConnectionStatusList) throws IOException {
        serverSocket = new ServerSocket(tcpPortNumber);
        connectionThreadList = Collections.synchronizedList(new LinkedList<>());
        clientSockets = Collections.synchronizedList(new LinkedList<>());
        this.dataManipulationService = dataManipulationService;
        this.tcpConnectionStatusList = tcpConnectionStatusList;
    }

    public static synchronized TCPServer getTCPServerInstance(
            int tcpPortNumber,
            DataManipulationService dataManipulationService,
            List<TCPConnectionStatus> tcpConnectionStatusList) throws IOException {
        if (tcpServer == null) {
            tcpServer = new TCPServer(tcpPortNumber, dataManipulationService, tcpConnectionStatusList);
        }
        return tcpServer;
    }

    public void shutdownTCPServer() throws IOException {
        for (Socket clientSocket : clientSockets) {
            clientSocket.close();
        }
        serverSocket.close();
        tcpServer = null;
        interrupt();
    }

    @Override
    public void run() {
        try {
            while (!isInterrupted()) {
                Socket clientSocket = serverSocket.accept();
                clientSockets.add(clientSocket);
                TCPConnectionStatus tcpConnectionStatus =
                        new TCPConnectionStatus(
                                clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort(),
                                new Date());
                tcpConnectionStatusList.add(tcpConnectionStatus);
                Thread clientConnectionThread =
                        new Thread(
                                new TCPClientConnectionThread(
                                        clientSocket,
                                        dataManipulationService,
                                        clientSockets,
                                        tcpConnectionStatus,
                                        tcpConnectionStatusList,
                                        connectionThreadList));
                connectionThreadList.add(clientConnectionThread);
                clientConnectionThread.start();
            }
        } catch (IOException ignored) {
        }
    }
}